using Microsoft.Kinect;
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using VideoMagic.Extensions;

namespace VideoMagic
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        static int _width = 640;
        static int _height = 480;

        KinectVideoMerge videoMerge = new KinectVideoMerge(_width, _height);
        VideoMagicImage currentFrame = new VideoMagicImage(_width, _height);
        VideoMagicImage currentFrameDepthStyle = new VideoMagicImage(_width, _height);

        IntPoint mousePosition;

        //float[] depthBuffer = new float[_width * _height];

        public static string[] Arguments { get; set; }

        public void ShowWindow()
        {
            this.Show();
        }

        public MainWindow()
        {
            InitializeComponent();
        }

        KinectSensor kinect;
        DateTime lastTime = DateTime.MaxValue;
        private bool _ShuttingDown;

        private void Window_Loaded(object sender, EventArgs e)
        {
            int kinectNumber = 0;

            if (Arguments != null)
            {
                if (!int.TryParse(Arguments[0], out kinectNumber))
                {
                    kinectNumber = 0;
                }
            }

            if (KinectSensor.KinectSensors.Count > kinectNumber)
            {
                kinect = KinectSensor.KinectSensors[kinectNumber];
            }
            else
            {
                throw new Exception(string.Format("Kinect sensor {0} not found", kinectNumber));
            }

            //kinectTransform = new KinectDepthTransform(kinect, DepthImageFormat.Resolution_widthx_heightFps30, ColorImageFormat.RgbResolution_widthx_heightFps30, kinect.DepthStream.UnknownDepth, kinect.DepthStream.TooNearDepth, kinect.DepthStream.TooFarDepth);

            //TransformSmoothParameters skeletonParameters = new TransformSmoothParameters();

            kinect.DepthStream.Range = DepthRange.Near;

            kinect.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);
            kinect.DepthStream.Enable(DepthImageFormat.Resolution640x480Fps30);
            //kinect.SkeletonStream.Enable(skeletonParameters);

            kinect.AllFramesReady += new EventHandler<AllFramesReadyEventArgs>(kinect_AllFramesReady);

            kinect.Start();
        }

        byte[] _redPixel = new byte[] { 0, 0, 255, 0 };
        byte[] _bluePixel = new byte[] { 255, 0, 0, 0 };

        void kinect_AllFramesReady(object sender, AllFramesReadyEventArgs e)
        {
            if (_ShuttingDown) { return; }

            ColorImageFrame colorFrame = e.OpenColorImageFrame();

            if (colorFrame != null)
            {
                colorFrame.CopyPixelDataTo(currentFrame.ColorData);
                colorFrame.Dispose();
                videoMerge.UpdateMainLayerColor(currentFrame);
                //kinectTransform.TransformColorToDepthFrame(currentFrame.ColorData, currentFrameDepthStyle.ColorData);
            }

            DepthImageFrame depthFrame = e.OpenDepthImageFrame();

            if (depthFrame != null)
            {
                //int depthLength = currentFrame.DepthData.Length;

                depthFrame.CopyPixelDataTo(currentFrame.DepthData);
                //depthFrame.CopyDepthImagePixelDataTo(currentFrame.DepthData);
                depthFrame.Dispose();


                //var pt = new ColorImagePoint { };

                //xxArray.Copy(currentFrame.DepthData, videoMerge.MainLayerDepth, depthLength);
                //kinectTransform.TransformDepthMapForColorFrame(currentFrame.DepthData, videoMerge.MainLayerDepth);
                ////xxkinectTransform.TransformDepthMapForColorFrame(currentFrame.DepthData, depthBuffer);
                //Array.Copy(currentFrame.DepthData, currentFrameDepthStyle.DepthData, depthLength);
            }

            currentFrame.UpdateBitmaps();

            //videoMerge.MergeToOutput(kinectTransform);
            videoMerge.UpdateImage(colorInputImage, depthInputImage, currentFrame);

            //videoMerge.UpdateOutputImage(colorOutputImage, null);

            //videoMerge.UpdateImage(depthVideoOverlayImage, depthVideoOverlayImage2, KinectVideoMerge.LayerName.Main);
            //videoMerge.UpdateImage(otherInputImage, depthVideoOverlayImage, KinectVideoMerge.LayerName.Foreground);

            videoMerge.Layers[KinectVideoMerge.LayerName.Background].ColorData.Fill(_redPixel);
            videoMerge.Layers[KinectVideoMerge.LayerName.Foreground].ColorData.Fill(_bluePixel);

            videoMerge.Layers[KinectVideoMerge.LayerName.Background].UpdateBitmaps();
            videoMerge.Layers[KinectVideoMerge.LayerName.Foreground].UpdateBitmaps();

            if (!mergeEffect.PropertySetComplete)
            {
                colorOutputImage.Source = videoMerge.Layers[KinectVideoMerge.LayerName.Background].ColorBitmap;

                mergeEffect.DepthInput1 = videoMerge.Layers[KinectVideoMerge.LayerName.Main].DepthBrush;
                mergeEffect.ColorInput1 = videoMerge.Layers[KinectVideoMerge.LayerName.Main].ColorBrush;

                mergeEffect.DepthInputBackground = videoMerge.Layers[KinectVideoMerge.LayerName.Background].DepthBrush;
                mergeEffect.ColorBackground = videoMerge.Layers[KinectVideoMerge.LayerName.Background].ColorBrush;

                mergeEffect.DepthInput2 = videoMerge.Layers[KinectVideoMerge.LayerName.Foreground].DepthBrush;
                mergeEffect.ColorInput2 = videoMerge.Layers[KinectVideoMerge.LayerName.Foreground].ColorBrush;

                mergeEffect.TooNear = kinect.DepthStream.TooNearDepth;
                mergeEffect.TooFar = kinect.DepthStream.TooFarDepth;
                mergeEffect.UnknownDistance = kinect.DepthStream.UnknownDepth;

                mergeEffect.PropertySetComplete = true;
            }

            //ShowMousePosition();
        }

        private void Window_Closed(object sender, EventArgs e)
        {
            _ShuttingDown = true;
            // Wait long enough for current frame to finish processing
            Thread.Sleep(100);
            kinect.Stop();
        }

        private void captureBackgroundButton_Click(object sender, RoutedEventArgs e)
        {
            videoMerge.CaptureBackground();
        }

        private void recordButton_Click(object sender, RoutedEventArgs e)
        {
            //videoMagic.Record(TimeSpan.FromSeconds(2));
        }

        private void fadeButton_Click(object sender, RoutedEventArgs e)
        {
            videoMerge.ShowHideMain();
        }

        private void colorInputImage_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            Point coords = e.GetPosition(colorOutputImage);
            mousePosition = new IntPoint(coords);

            ShowMousePosition();
        }

        void ShowMousePosition()
        {
            //if (mousePosition.Y > -1 && mousePosition.X > -1 && mousePosition.Y < _height && mousePosition.X < _width)
            //{
            //    var depth = currentFrame.DepthData[mousePosition.Y * _width + mousePosition.X];
            //    mouseCoords.Text = depth.Depth.ToString();
            //}
        }

        bool switchImage = false;
        private void QRButton_Click(object sender, RoutedEventArgs e)
        {
            if (switchImage)
            {
                LoadImageSetToLayer("thanksforcoming", KinectVideoMerge.LayerName.Foreground);
            }
            else
            {
                LoadImageSetToLayer("welcome", KinectVideoMerge.LayerName.Foreground);
            }
            switchImage = !switchImage;
        }

        void LoadImageSetToLayer(string setName, KinectVideoMerge.LayerName layer)
        {
            LoadImageSetToLayer(setName, layer, false);
        }

        void LoadImageSetToLayer(string setName, KinectVideoMerge.LayerName layer, bool failSilentIfNotFound)
        {
            var imageFileName = setName + ".png";
            var depthImageFileName = setName + "-depth.bmp";

            if (!File.Exists(imageFileName) || !File.Exists(depthImageFileName))
            {
                return;
            }

            var imageSet = new VideoMagicImage(_width, _height);

            var src = new BitmapImage(new Uri(imageFileName, UriKind.Relative));
            src.CopyPixels(imageSet.ColorData, 4 * _width, 0);

            var depthSrc = new BitmapImage(new Uri(depthImageFileName, UriKind.Relative));
            var convertBitmap = new FormatConvertedBitmap();

            convertBitmap.BeginInit();
            convertBitmap.Source = depthSrc;
            convertBitmap.DestinationFormat = PixelFormats.Gray16;
            convertBitmap.EndInit();

            convertBitmap.CopyPixels(imageSet.DepthData, imageSet.DepthStride, 0);

            imageSet.UpdateBitmaps();
            videoMerge.SetLayer(layer, imageSet);
        }

        private void saveBackgroundButton_Click(object sender, RoutedEventArgs e)
        {
            VideoMagicImage background = videoMerge.Layers[KinectVideoMerge.LayerName.Background];
            WriteableBitmap colorBitmap = background.ColorBitmap;
            WriteableBitmap depthBitmap = background.DepthBitmap;

            using (FileStream stream = new FileStream("new.png", FileMode.Create))
            {
                PngBitmapEncoder encoder = new PngBitmapEncoder();
                encoder.Frames.Add(BitmapFrame.Create(colorBitmap));
                encoder.Save(stream);
            }

            using (FileStream stream = new FileStream("new-depth.bmp", FileMode.Create))
            {
                BmpBitmapEncoder encoder = new BmpBitmapEncoder();
                encoder.Frames.Add(BitmapFrame.Create(depthBitmap));
                encoder.Save(stream);
            }
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            this.SizeToContent = System.Windows.SizeToContent.Manual;
            this.WindowState = System.Windows.WindowState.Maximized;
            Column1.Visibility = System.Windows.Visibility.Collapsed;
            colorOutputImage.Height = .9 * System.Windows.SystemParameters.PrimaryScreenHeight;
            colorOutputImage.Width = .9 * System.Windows.SystemParameters.PrimaryScreenWidth;
        }

        private void loadBackgroundButton_Click(object sender, RoutedEventArgs e)
        {
            LoadImageSetToLayer("new", KinectVideoMerge.LayerName.Background, true);
        }
    }
}
